package com.yl.chainStore.services.impl

import com.alibaba.druid.support.json.JSONUtils
import com.alibaba.fastjson.JSONObject
import com.yl.chainStore.common.annotations.CompanyUserOperationLogColumn
import com.yl.chainStore.common.enums.Status
import com.yl.chainStore.common.enums.TypeEnum
import com.yl.chainStore.entity.user.CompanyUserOperationLog
import com.yl.chainStore.entity.user.CompanyUserOperationLogDetail
import com.yl.chainStore.mapper.user.CompanyUserOperationLogDetailMapper
import com.yl.chainStore.mapper.user.CompanyUserOperationLogMapper
import com.yl.chainStore.pojo.vo.system.QueryHtmlConfigVo
import com.yl.chainStore.services.ICompanyDictionaryService
import com.yl.chainStore.services.ICompanyHtmlConfigService
import com.yl.chainStore.services.ICompanyUserOperationLogService
import com.yl.chainStore.services.ICustomerInfoService
import com.yl.chainStore.services.sick.ICustomerSubscribeLogService
import com.yl.chainStore.util.dateTimeFormat
import com.yl.common.control.ResponseBody
import com.yl.common.control.returnSuccess
import com.yl.common.getContext
import com.yl.users.services.ICompanyDeptService
import com.yl.users.services.ICompanyUserService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.lang.reflect.Field
import java.util.*

@Service
class CompanyUserOperationLogServiceImpl(
	private val companyUserOperationLogMapper: CompanyUserOperationLogMapper,
	private val companyUserOperationLogDetailMapper: CompanyUserOperationLogDetailMapper,

	) : ICompanyUserOperationLogService {

	@Autowired
	private lateinit var iCompanyHtmlConfigService: ICompanyHtmlConfigService

	@Autowired
	private lateinit var iCompanyUserService: ICompanyUserService

	@Autowired
	private lateinit var iCustomerInfoService: ICustomerInfoService

	@Autowired
	private lateinit var iCompanyDictionaryService: ICompanyDictionaryService

	@Autowired
	private lateinit var iCompanyDeptService: ICompanyDeptService

	@Autowired
	private lateinit var iCustomerSubscribeLogService: ICustomerSubscribeLogService

	override fun addLog(
		associatedId: Long,
		modelType: TypeEnum,
		tableType: TypeEnum,
		updateType: TypeEnum,
		beforeObj: Any?,
		afterObj: Any?,
		customerId: Long?,
		createUserId: Long?
	): ResponseBody {
		val log = CompanyUserOperationLog(
			id = 0L,
			associatedId = associatedId,
			modelType = modelType,
			tableType = tableType,
			updateType = updateType,
			customerId = customerId,
			createUserId = createUserId ?: getContext().userId
		)
		return addLog(log, beforeObj, afterObj)
	}

	override fun addLog(userLog: CompanyUserOperationLog, beforeObj: Any?, afterObj: Any?): ResponseBody {
		setDetail(userLog, beforeObj, afterObj)
		return addLog(userLog)
	}

	override fun addLog(userLog: CompanyUserOperationLog): ResponseBody {
		if (userLog.details == null || userLog.details!!.isEmpty()) {
			return returnSuccess()
		}
		companyUserOperationLogMapper.insert(userLog)
		for (detail in userLog.details!!) {
			detail.logId = userLog.id
			companyUserOperationLogDetailMapper.insert(detail)
		}
		return returnSuccess()
	}


	/**
	 * 对比对象 把变更记录存进details
	 */
	private fun setDetail(log: CompanyUserOperationLog, beforeObj: Any?, afterObj: Any?) {
		if (beforeObj == null && afterObj == null) {
			return
		}
		if (beforeObj == null) {
			//添加添加记录
			setAddDetail(log, afterObj!!)
			return
		}
		if (afterObj == null) {
			//添加添加记录
			setDelDetail(log, beforeObj)
			return
		}

		if (beforeObj.javaClass != afterObj.javaClass) {
			return
		}
		val oldFs = beforeObj.javaClass.declaredFields
		val newFs = afterObj.javaClass.declaredFields
		val oldMap = eqFieldsToMap(beforeObj, oldFs)
		val newMap = eqFieldsToMap(afterObj, newFs)
		val list = mutableListOf<CompanyUserOperationLogDetail>()
		try {
			for ((filed, vo) in oldMap) {
				var newObj: Any? = null
				if (newMap[filed] != null) {
					newObj = newMap[filed]!!.value
				}
				eqColumnAndAddDetailToList(list,
					log.groupId,
					vo.columnType,
					filed,
					vo.name,
					vo.value,
					newObj)
			}
		} catch (e: java.lang.Exception) {
			e.printStackTrace()
		}
		log.details = list
	}

	/**
	 * 对象添加处理日志（从无到有）
	 */
	private fun setAddDetail(log: CompanyUserOperationLog, afterObj: Any) {
		val fs = afterObj.javaClass.declaredFields
		val list = mutableListOf<CompanyUserOperationLogDetail>()
		for (f in fs) {

			val showField: CompanyUserOperationLogColumn =
				f.getAnnotation(CompanyUserOperationLogColumn::class.java) ?: continue
			f.isAccessible = true
			eqColumnAndAddDetailToList(
				list,
				log.groupId,
				showField.columnType,
				f.name,
				showField.value,
				null,
				f.get(afterObj),

			)
		}
		log.details = list
	}

	/**
	 * 对象删除处理日志（从有到无）
	 */
	private fun setDelDetail(log: CompanyUserOperationLog, afterObj: Any) {
		val fs = afterObj.javaClass.declaredFields
		val list = mutableListOf<CompanyUserOperationLogDetail>()
		for (f in fs) {
			val showField: CompanyUserOperationLogColumn =
				f.getAnnotation(CompanyUserOperationLogColumn::class.java) ?: continue
			f.isAccessible = true
			eqColumnAndAddDetailToList(
				list,
				log.groupId,
				showField.columnType,
				f.name,
				showField.value,
				f.get(afterObj),
				null,
			)
		}
		log.details = list
	}

	/**
	 * 对比参数，并把结果加入列表
	 */
	private fun eqColumnAndAddDetailToList(
		list: MutableList<CompanyUserOperationLogDetail>,
		groupId: Long?,
		columnType: TypeEnum,
		filedName: String,
		columnShowName: String?,
		beforeValue: Any?,
		afterValue: Any?
	) {
		//对象不一样
		if (!newEq(beforeValue, afterValue)) {
			var setShowName = ""
			if (columnShowName.isNullOrEmpty() && groupId != null) {
				val oneConfig =
					iCompanyHtmlConfigService.getOneConfig(QueryHtmlConfigVo(groupId = groupId, name = filedName))

				if (oneConfig != null) {
					setShowName = oneConfig.viewName
				}
			} else {
				setShowName = columnShowName ?: ""
			}
			when (columnType) {
				TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_TYPE_DEFAULT -> {
					//基础类型
					list.add(
						CompanyUserOperationLogDetail(
							columnValue = filedName,
							columnShowName = setShowName,
							columnShowAllName = setShowName,
							beforeValue = newToString(beforeValue),
							afterValue = newToString(afterValue)
						)
					)
					return
				}
				TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_COMPANY_USER -> {
					var beforeName: String? = null
					var afterName: String? = null

					if (beforeValue != null) {
						try {
							val user = iCompanyUserService.getUser(beforeValue as Long)
							if (user != null) {
								beforeName = user.realName
							}
						} catch (e: Exception) {
							e.printStackTrace()
						}
					}
					if (afterValue != null) {
						try {
							val user = iCompanyUserService.getUser(afterValue as Long)
							if (user != null) {
								afterName = user.realName
							}
						} catch (e: Exception) {
							e.printStackTrace()
						}
					}
					list.add(
						CompanyUserOperationLogDetail(
							columnValue = filedName,
							columnShowName = setShowName,
							columnShowAllName = setShowName,
							beforeValue = newToString(beforeName),
							afterValue = newToString(afterName)
						)
					)
					return
				}
				TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_CUSTOMER_INFO -> {
					var beforeName: String? = null
					var afterName: String? = null

					if (beforeValue != null) {
						try {
							val user = iCustomerInfoService.getById(beforeValue as Long)
							if (user != null) {
								beforeName = user.name
							}
						} catch (e: Exception) {
							e.printStackTrace()
						}
					}
					if (afterValue != null) {
						try {
							val user = iCustomerInfoService.getById(afterValue as Long)
							if (user != null) {
								afterName = user.name
							}
						} catch (e: Exception) {
							e.printStackTrace()
						}
					}
					list.add(
						CompanyUserOperationLogDetail(
							columnValue = filedName,
							columnShowName = setShowName,
							columnShowAllName = setShowName,
							beforeValue = newToString(beforeName),
							afterValue = newToString(afterName)
						)
					)
					return
				}
				TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_JSON -> {
					val beforeJson =
						if(beforeValue != null){
							if(beforeValue is Map<*, *>){
								JSONObject.parseObject(JSONUtils.toJSONString(beforeValue))
							}else{
								JSONObject.parseObject(beforeValue.toString())
							}
						}else{
							null
						}
					val afterJson =
						if(beforeValue != null){
							if(afterValue is Map<*, *>){
								JSONObject.parseObject(JSONUtils.toJSONString(afterValue))
							}else{
								JSONObject.parseObject(afterValue.toString())
							}
						}else{
							null
						}
					list.addAll(
						jsonEq(
							filedName+ ".",
							setShowName + "=>",
							groupId,
							beforeJson,
							afterJson
						)
					)

					return
				}
				TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_SICK_LABEL -> {
					var beforeLabel = ""
					var afterLabel =""
					if(beforeValue != null){
						if(beforeValue.toString().isNotEmpty()){
							val split = beforeValue.toString().split(",")
							for(s in split){
								if(s.isEmpty()){
									continue
								}
								val detail = iCompanyDictionaryService.getDetail(s.toLong()) ?: continue
								if(detail.itemName.isEmpty()){
									continue
								}
								beforeLabel += (detail.itemName+" ")
							}
						}
					}
					if(afterValue != null){
						if(afterValue.toString().isNotEmpty()){
							val split = afterValue.toString().split(",")
							for(s in split){
								if(s.isEmpty()){
									continue
								}
								val detail = iCompanyDictionaryService.getDetail(s.toLong()) ?: continue
								if(detail.itemName.isNullOrEmpty()){
									continue
								}
								afterLabel += (detail.itemName+" ")
							}
						}
					}
					list.add(
						CompanyUserOperationLogDetail(
							columnValue = filedName,
							columnShowName = setShowName,
							columnShowAllName = setShowName,
							beforeValue = beforeLabel,
							afterValue = afterLabel
						)
					)
					return
				}

				TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_TYPE_ENUM -> {
					var beforeType = "无"
					var afterType = "无"
					if(beforeValue != null){
						beforeType = (beforeValue as TypeEnum).typeName
					}
					if(afterValue != null){
						afterType = (afterValue as TypeEnum).typeName
					}
					list.add(
						CompanyUserOperationLogDetail(
							columnValue = filedName,
							columnShowName = setShowName,
							columnShowAllName = setShowName,
							beforeValue = beforeType,
							afterValue = afterType
						)
					)
					return
				}
				TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_STATUS_ENUM -> {
					var beforeType = "无"
					var afterType = "无"
					if(beforeValue != null){
						beforeType = (beforeValue as Status).show
					}
					if(afterValue != null){
						afterType = (afterValue as Status).show
					}
					list.add(
						CompanyUserOperationLogDetail(
							columnValue = filedName,
							columnShowName = setShowName,
							columnShowAllName = setShowName,
							beforeValue = beforeType,
							afterValue = afterType
						)
					)
					return
				}
				TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_DATE_TIME -> {
					var beforeDay :String ?= ""
					var afterDay :String ?= ""
					if(beforeValue != null){
						beforeDay = dateTimeFormat(beforeValue as Date)
					}
					if(afterValue != null){
						afterDay = dateTimeFormat(afterValue as Date)
					}
					list.add(
						CompanyUserOperationLogDetail(
							columnValue = filedName,
							columnShowName = setShowName,
							columnShowAllName = setShowName,
							beforeValue = beforeDay,
							afterValue = afterDay
						)
					)
					return
				}
				TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_DEPT-> {
					var beforeName: String? = null
					var afterName: String? = null

					if (beforeValue != null) {
						try {
							val dept = iCompanyDeptService.getDept(beforeValue as Long)
							if (dept != null) {
								beforeName = dept.name
							}
						} catch (e: Exception) {
							e.printStackTrace()
						}
					}
					if (afterValue != null) {
						try {
							val dept = iCompanyDeptService.getDept(afterValue as Long)
							if (dept != null) {
								afterName = dept.name
							}
						} catch (e: Exception) {
							e.printStackTrace()
						}
					}
					list.add(
						CompanyUserOperationLogDetail(
							columnValue = filedName,
							columnShowName = setShowName,
							columnShowAllName = setShowName,
							beforeValue = newToString(beforeName),
							afterValue = newToString(afterName)
						)
					)
					return
				}
				TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_SUBSCRIBE_LOG_ITEMS -> {
					var beforeLabel = ""
					var afterLabel =""
					if(beforeValue != null){
						if(beforeValue.toString().isNotEmpty()){
							val split = beforeValue.toString().split(",")
							val re = mutableListOf<Long>()
							for (s in split) {
								if (s.isEmpty()) {
									continue
								}
								re.add(s.toLong())
							}
							beforeLabel = iCustomerSubscribeLogService.getSubscribeItemsByIdsStr(re)
						}
					}
					if(afterValue != null){
						if(afterValue.toString().isNotEmpty()){
							val split = afterValue.toString().split(",")
							val re = mutableListOf<Long>()
							for (s in split) {
								if (s.isEmpty()) {
									continue
								}
								re.add(s.toLong())
							}
							afterLabel =  iCustomerSubscribeLogService.getSubscribeItemsByIdsStr(re)
						}
					}
					list.add(
						CompanyUserOperationLogDetail(
							columnValue = filedName,
							columnShowName = setShowName,
							columnShowAllName = setShowName,
							beforeValue = beforeLabel,
							afterValue = afterLabel
						)
					)
					return
				}
				else -> {
					list.add(
						CompanyUserOperationLogDetail(
							columnValue = filedName,
							columnShowName = setShowName,
							columnShowAllName = setShowName,
							beforeValue = newToString(beforeValue),
							afterValue = newToString(afterValue)
						)
					)
					return
				}
			}
		}
	}

	/**
	 * 将字段列表变成map的形式
	 */
	private fun eqFieldsToMap(o: Any, fs: Array<Field>): MutableMap<String, ObjectEqualsVo> {
		val resMap = mutableMapOf<String, ObjectEqualsVo>()
		for (f in fs) {
			val showField: CompanyUserOperationLogColumn =
				f.getAnnotation(CompanyUserOperationLogColumn::class.java) ?: continue
			f.isAccessible = true
			resMap[f.name] = ObjectEqualsVo(
				f.get(o),
				showField.value,
				showField.columnType
			)
		}
		return resMap
	}

	/**
	 * 对比基础类型
	 */
	private fun newEq(before: Any?, after: Any?): Boolean {
		if (before == null && after == null) {
			return true
		}
		if (before == null || after == null) {
			if(before == "" || after == "" ){
				return true
			}
			return false
		}

		return before == after
	}

	private fun newToString(obj: Any?): String {
		if (obj != null) {
			return obj.toString()
		}
		return "无"
	}


	private fun jsonEq(
		prefixFiledName: String,
		prefixShowName: String,
		groupId: Long?,
		beforeObj: JSONObject?,
		afterObj: JSONObject?
	): MutableList<CompanyUserOperationLogDetail> {
		val resList = mutableListOf<CompanyUserOperationLogDetail>()
		if(newEq(beforeObj,afterObj)){
			return resList
		}
		//获取键 set
		val keys = beforeObj?.keys ?: afterObj!!.keys
		for(key in keys){
			val beforeValue:Any? = if(beforeObj != null){
				beforeObj[key]
			}else{
				null
			}
			val afterValue:Any? = if(afterObj != null){
				afterObj[key]
			}else{
				null
			}
			var showName = ""
			if ( groupId != null) {
				val oneConfig =
					iCompanyHtmlConfigService
						.getOneConfig(QueryHtmlConfigVo(groupId = groupId
							, name = prefixFiledName+key))

				if (oneConfig != null) {
					showName = oneConfig.viewName
				}
			} else {
				showName = key
			}

			if(isJson(beforeValue,afterValue)){
				val beforeJson =
					if(beforeValue != null){
						if(beforeValue is Map<*, *>){
							JSONObject.parseObject(JSONUtils.toJSONString(beforeValue))
						}else{
							JSONObject.parseObject(beforeValue.toString())
						}
					}else{
						null
					}
				val afterJson =
					if(afterValue != null){
						if(afterValue is Map<*, *>){
							JSONObject.parseObject(JSONUtils.toJSONString(afterValue))
						}else{
							JSONObject.parseObject(afterValue.toString())
						}
					}else{
						null
					}

				 resList.addAll(
					jsonEq(
						prefixFiledName + key + ".",
						prefixShowName + showName + "=>",
						groupId,
						beforeJson,
						afterJson
					)
				)
			}else{
				resList.add(createDetail(
					prefixFiledName + key ,
					showName,
					prefixShowName + showName ,
					beforeValue,
					afterValue))
			}



		}
		return resList
	}

	private fun isJson(beforeObj: Any?,afterObj: Any?):Boolean{
		if(beforeObj == null && afterObj == null){
			return false
		}
		try {
			JSONObject.parseObject(beforeObj.toString())
			return true
		} catch (e: Exception) {

		}
		try {
			JSONObject.parseObject(afterObj.toString())
			return true
		} catch (e: Exception) {

		}
		return false
	}

	/**
	 * 对比json的值
	 */
	private fun createDetail(filedName: String,
	                        showName: String,
	                           showAllName:String,
	                        beforeObj: Any?,
	                        afterObj: Any?): CompanyUserOperationLogDetail{

		return CompanyUserOperationLogDetail(
			columnValue = filedName,
			columnShowName = showName,
			columnShowAllName = showAllName,
			beforeValue = newToString(beforeObj),
			afterValue = newToString(afterObj)
		)

	}



//	private fun jsonArrayEq(
//		prefixFiledName: String,
//		prefixShowName: String,
//		beforeObj: JSONArray,
//		afterObj: JSONArray
//	): MutableList<CompanyUserOperationLogDetail> {
//		val resList = mutableListOf<CompanyUserOperationLogDetail>()
//
//		return resList
//	}

}

data class ObjectEqualsVo(
	/**
	 * 值
	 */
	val value: Any?=null,

	/**
	 * 显示名称
	 */
	var name: String,

	//字段类型 1111 - 1200
	val columnType: TypeEnum = TypeEnum.COMPANY_USER_OPERATION_LOG_COLUMN_TYPE_DEFAULT
)

